package com.ruoyi.utils;

import cn.hutool.core.thread.ThreadException;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ruoyi.common.utils.uuid.IdUtils;
import lombok.Data;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;

public class QRCodeGeneratorUtil {

    /**
     * 生成二维码到文件
     */
    public static byte[] generateQRCodeToByte(QRCodeConfig config) {
        try {
            BufferedImage image = generateQRCodeMJImage(config);
            //ImageIO.write(image, "PNG", new File(config.getFilePath()));
            System.out.println("二维码生成成功: " + config.getFilePath());
            byte[] pngs = generateQRCodeBytes(image, "PNG");
            return pngs;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static BufferedImage generateQRCodeToImage(QRCodeConfig config) {
        try {
            BufferedImage image = generateQRCodeImage(config);
            //byte[] pngs = imageToBytes(image, "PNG");
            //ImageIO.write(image, "PNG", new File(config.getFilePath()));
            //System.out.println("二维码生成成功: " + config.getFilePath());
            return image;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 生成二维码字节数组
     */
    private static byte[] generateQRCodeBytes(BufferedImage image, String format) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            ImageIO.write(image, format, baos);
            return baos.toByteArray();
        } catch (Exception e) {
            throw new ThreadException("图片转换失败: " + e.getMessage(), e);
        }
    }

    /**
     * 生成二维码图片对象
     */
    public static BufferedImage generateQRCodeImage(QRCodeConfig config) {
        try {
            //int widthPx = mmToPixels(config.getWidthMM(), config.getDpi());
            //int heightPx = mmToPixels(config.getHeightMM(), config.getDpi());

            int widthPx = mmToPixels(config.getWidthMM() * 0.8, Math.max(config.getDpi(), 200));
            int heightPx = mmToPixels(config.getHeightMM() * 0.8, Math.max(config.getDpi(), 200));

            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, config.getCharset());
            hints.put(EncodeHintType.ERROR_CORRECTION, config.getErrorCorrectionLevel());
            hints.put(EncodeHintType.MARGIN, config.getMargin());
            //hints.put(EncodeHintType.QR_VERSION, 1); // 强制使用较小的版本

            BitMatrix bitMatrix = new MultiFormatWriter().encode(
                    config.getContent(), BarcodeFormat.QR_CODE, widthPx, heightPx, hints);

            BufferedImage image = new BufferedImage(
                    widthPx, heightPx, BufferedImage.TYPE_INT_RGB);

            for (int x = 0; x < widthPx; x++) {
                for (int y = 0; y < heightPx; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ?
                            config.getForegroundColor().getRGB() :
                            config.getBackgroundColor().getRGB());
                }
            }

            return image;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static BufferedImage generateQRCodeMJImage(QRCodeConfig config) {
        try {
            int widthPx, heightPx;

            if (config.isDenseMode()) {
                // 密集模式：小尺寸 + 高DPI
                widthPx = mmToPixels(config.getWidthMM() * config.getDenseScale(), config.getDenseDpi());
                heightPx = mmToPixels(config.getHeightMM() * config.getDenseScale(), config.getDenseDpi());
            } else {
                // 普通模式
                widthPx = mmToPixels(config.getWidthMM(), config.getDpi());
                heightPx = mmToPixels(config.getHeightMM(), config.getDpi());
            }

            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, config.getCharset());
            hints.put(EncodeHintType.ERROR_CORRECTION, config.getErrorCorrectionLevel());
            hints.put(EncodeHintType.MARGIN, config.getMargin());

            BitMatrix bitMatrix = new MultiFormatWriter().encode(
                    config.getContent(), BarcodeFormat.QR_CODE, widthPx, heightPx, hints);

            BufferedImage image = new BufferedImage(
                    widthPx, heightPx, BufferedImage.TYPE_INT_RGB);

            for (int x = 0; x < widthPx; x++) {
                for (int y = 0; y < heightPx; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ?
                            config.getForegroundColor().getRGB() :
                            config.getBackgroundColor().getRGB());
                }
            }

            return image;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static int mmToPixels(double mm, int dpi) {
        return (int) Math.round((mm / 25.4) * dpi);
    }

    // 配置类
    @Data
    public static class QRCodeConfig {
        private String content;
        private double widthMM = 15;
        private double heightMM = 15;
        private int dpi = 300;
        private String filePath = "D:\\service\\upload\\qrcode.png";
        private String charset = "UTF-8";
        private ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.M;
        private int margin = 0;
        private Color foregroundColor = Color.BLACK;
        private Color backgroundColor = Color.WHITE;

        // 新增密集模式配置
        private boolean denseMode = true; // 是否启用密集模式
        private double denseScale = 0.3;   // 密集模式缩放比例
        private int denseDpi = 800;        // 密集模式DPI

        // 构造函数、getter和setter方法
        public QRCodeConfig(String content) {
            this.content = content;
        }

    }

    public static void main(String[] args) {
        // 使用示例
        QRCodeConfig config = new QRCodeConfig(IdUtils.fastSimpleUUID());
        config.setWidthMM(15);
        config.setHeightMM(15);
        config.setDpi(300);
        config.setFilePath("D:\\service\\upload\\qrcode.png");
        config.setForegroundColor(Color.BLACK);
        config.setBackgroundColor(Color.WHITE);

//        generateQRCodeToFile(config);
    }
}
